/*!
    \file  link32fa016bx_spih.c
    \brief SPI Host driver

    \version 2024-2-21, V1.0.0, firmware for Link32FA016BX
*/


#include "link32fa016bx_spih.h"

void spih_deinit(uint32_t spih_periph)
{
    switch (spih_periph) {
        case SPIH0:
            /* reset SPIH0 */
            rcu_periph_reset_enable(RCU_RST_SPIH0);
            rcu_periph_reset_disable(RCU_RST_SPIH0);
            rcu_periph_clock_disable(RCU_CLKON_SPIH0);
            break;
        case SPIH1:
            /* reset SPIH1*/
            rcu_periph_reset_enable(RCU_RST_SPIH1);
            rcu_periph_reset_disable(RCU_RST_SPIH1);
            rcu_periph_clock_disable(RCU_CLKON_SPIH1);
            break;
        default :
            break;
    }
}

/*!
    \brief      initialize the parameters of SPI struct with the default values
    \param[in]  spih_struct: SPI parameter stuct
    \param[out] none
    \retval     none
*/
void spih_struct_para_init(spih_parameter_struct* spih_struct)
{
    /* set the SPI struct with the default values */
    spih_struct->spi_pol_pha   = SPIH_CK_PL_LOW_PH_1EDGE;
    spih_struct->csn_lead_time = 1;
    spih_struct->csn_tail_time = 1;
    spih_struct->csn_idle_time = 2;
    spih_struct->clk_div       = 8;
}

/*!
    \brief      initialize SPI parameter
    \param[in]  spih_periph: SPIx(x=0,1,2)
    \param[in]  spih_struct: SPI parameter initialization stuct members of the structure
    \param[out] none
    \retval     none
*/
void spih_init(uint32_t spih_periph, spih_parameter_struct* spih_struct)
{
    switch (spih_periph) {
        case SPIH0:
    		rcu_periph_clock_enable(RCU_CLKON_SPIH0);
            break;
        case SPIH1:
    		rcu_periph_clock_enable(RCU_CLKON_SPIH1);
            break;
        default :
            break;
    }
    SPIH_CFG(spih_periph) = \
        ((spih_struct->clk_div << SPIH_CFG_CLKDIV_Pos) & SPIH_CFG_CLKDIV_Msk) | \
	((spih_struct->csn_idle_time << SPIH_CFG_CSNIDLE_Pos) & SPIH_CFG_CSNIDLE_Msk) | \
	((spih_struct->csn_tail_time << SPIH_CFG_CSNTRAIL_Pos) & SPIH_CFG_CSNTRAIL_Msk) | \
	((spih_struct->csn_lead_time << SPIH_CFG_CSNLEAD_Pos) & SPIH_CFG_CSNLEAD_Msk) | \
	((spih_struct->spi_pol_pha << SPIH_CFG_CPHA_Pos) & SPIH_CFG_CPOL_Msk);
}

/*!
    \brief      enable SPI Host
    \param[in]  spih_periph: SPIx(x=0,1,2)
    \param[out] none
    \retval     none
*/
void spih_enable(uint32_t spih_periph)
{
    SPIH_CTL(spih_periph) |= (uint32_t)SPIH_CTL_SPIEN_Msk;
}

/*!
    \brief      disable SPI Host
    \param[in]  spih_periph: SPIx(x=0,1,2)
    \param[out] none
    \retval     none
*/
void spih_disable(uint32_t spih_periph)
{
    SPIH_CTL(spih_periph) &= (uint32_t)(~SPIH_CTL_SPIEN_Msk);
}


/*!
    \brief      enable SPI NSS output
    \param[in]  spih_periph: SPIx(x=0,1,2)
    \param[out] none
    \retval     none
*/
void spih_lines_enable(uint32_t spih_periph)
{
    SPIH_CTL(spih_periph) |= (uint32_t)SPIH_CTL_OUTPUT_EN_Msk;
}

/*!
    \brief      disable SPI NSS output
    \param[in]  spih_periph: SPIx(x=0,1,2)
    \param[out] none
    \retval     none
*/
void spih_lines_disable(uint32_t spih_periph)
{
    SPIH_CTL(spih_periph) &= (uint32_t)(~SPIH_CTL_OUTPUT_EN_Msk);
}


void spih_set_command(uint32_t spih_periph, spih_command_struct *spih_cmd)
{
    while(!(SPIH_STAT(spih_periph) & SPIH_STAT_READY_Msk));
    SPIH_CMD(spih_periph) = \
       ((spih_cmd->len << SPIH_CMD_LEN_Pos) & SPIH_CMD_LEN_Msk) | \
       ((spih_cmd->csnat << SPIH_CMD_CSAAT_Pos) & SPIH_CMD_CSAAT_Msk) | \
       ((spih_cmd->speed << SPIH_CMD_SPEED_Pos) & SPIH_CMD_SPEED_Msk) | \
       ((spih_cmd->dir << SPIH_CMD_DIRECTION_Pos) & SPIH_CMD_DIRECTION_Msk);
}

/*!
    \brief      SPI transmit data
    \param[in]  spih_periph: SPIx(x=0,1,2)
    \param[in]  data: 16-bit data
    \param[out] none
    \retval     none
*/
void spih_data_transmit(uint32_t spih_periph, uint32_t data)
{
    while(SPIH_STAT(spih_periph) & SPIH_STAT_TXFULL_Msk);
    SPIH_TXD(spih_periph) = data;
}

/*!
    \brief      SPI receive data
    \param[in]  spih_periph: SPIx(x=0,1,2)
    \param[out] none
    \retval     16-bit data
*/
uint32_t spih_data_receive(uint32_t spih_periph)
{
    while(SPIH_STAT(spih_periph) & SPIH_STAT_RXEMPTY_Msk);
    return SPIH_RXD(spih_periph);
}

uint32_t spih_data_transceive(uint32_t spih_periph, uint32_t data)
{
    spih_data_transmit(spih_periph, data);
    return spih_data_receive(spih_periph);
}

void spih_waiting_for_end(uint32_t spih_periph)
{
	while(SPIH_STAT(SPIH0) & SPIH_STAT_ACTIVE_Msk);
	return;
}

